from .gui import *

class UrlsListPanelControl(UrlsListPanelGUI):

    def __init__(self, parent=None):
        super().__init__(parent=parent)

    def _get_bulid_data(self)->List[App]:
        """获取构建数据（数据的二次处理与匹配）
        
            构建原理：宽搜
        """

        '''
            数据初始化
        '''
        self._clear_datas()

        # urls_data: Path = djangotools.get_urls_list_tree() # 获取原始的数据（根节点无实际用途）
        try:
            self.urls_data: Path = djangotools.get_urls_list_tree() # 获取原始的数据--（根节点无实际用途）
        except Exception as e:
            print("错误：", e) # 软件调试用（本功能未稳定前，不准备删除）【言外之意--永远不会删除】
            return []
        if self.urls_data is None: return []

        url_prefix = f'{env.getDjangoRunHost()}:{env.getDjangoRunPort()}/' # 路由前缀

        root_app = App('A-root-urls') # 根路由的存储容器（名称固定为 A-root-urls ）
        stack_urls: List[PathHelper] = [] # 栈
        show_nodes: List[App] = [root_app,] # 用于最终展示的节点（只存储每个树结构的根）

        # 首先初始化所有根节点的初始状态，以及节点容器（此处解决方案迸发于经验和灵感）
        for _ in self.urls_data.children:
            if _.isApp:
                temp_app = App(_.app_name)
                stack_urls.append(PathHelper(_, temp_app))
                show_nodes.append(temp_app) # 此处追加的节点将会在前端显示
            else:
                stack_urls.append(PathHelper(_, root_app))

        while len(stack_urls) > 0:
            pop_url: PathHelper = stack_urls.pop()
            pop_path: Path = pop_url.path
            pop_app: App = pop_url.app # 此处的作用只是为了扩展节点

            isNode: bool = pop_path.isNode
            isApp: bool = pop_path.isApp # （未用到）
            origin_str: str = pop_path.origin_str # origin_str 仅在 isNode = False 的时候有用
            node_str: str = pop_path.node_str # node_str 仅在 isNode = True 的时候有用

            '''
                获取 Url 对象的必要参数
            '''
            if not isNode: # 不是节点，定是展示行（仅此处分支插入行数据，程序的唯一出口）
                
                ''' origin_str
                    情形一：path('home/', views.home, name='index')
                    情形二：path('password_change/', wrap(self.password_change, cacheable=True), name='password_change'),
                '''
                sp_str = djangotools.get_url_genway_name(origin_str)
                one_path = sp_str[0].strip().strip("'\"/") # 获取路径片段 'home/'
                if "" != one_path: one_path += "/" # 规范化路径片段
                gen_way = sp_str[1] # 获取代码生成方式 views.home
                alias = "" # 路径别名
                for _ in sp_str[2:]: # DJango 的 路由语法，第二个参数往后全部是关键字参数
                    try:
                        k, v = _.split('=')
                    except:
                        raise PathArgsError("请使用正确的路由语法！")
                    else:
                        if "name" == k.strip(): # 对 name='index' 的拆解，取出路由代码 index
                            alias = v.strip().strip("'\"")
                            break
                    # 这里以后可以增加对路由参数的捕捉（功能会指数级扩展，底子还没有牢固）
                
                up_path = pop_path.relate_url + one_path # 拼接完整的相对路由
                pop_path.relate_url = up_path
                pop_path.split_path.append(one_path) # 必须加上分解路径才能完整（加上边界值，最后的边界值）【末级节点仅属于自己，不会影响其它任何路由】
                url = Url(
                    pop_app.name if pop_app.name else '无缝衔接', gen_way, alias if alias else "无",
                    up_path, url_prefix + up_path, str(pop_path.split_path),
                    pop_path.app_file, pop_path.app_name, pop_path.code_app_name,
                    str(pop_path.level)
                )
                pop_app.urls.append(url)

                self.full_paths.append(url) # 对所有的直接路由进行存储（用于搜索引擎的工作）
                self.split_urls.append(pop_path.split_path) # 用于修改功能

            else: # 节点的情况（分两种，一种是简单展开（当前路由作用域内展开），一种是应用程序展开（跳转到其它路由作用域），统一处理）
                '''
                    node_name 在特殊情况下要特殊处理
                '''
                if 'admin.site.urls' in node_str: # （当前路由节点）
                    node_name = node_str.replace('admin.site.urls', '').strip(string.whitespace+',"\'/')
                else:
                    node_name = node_str[:node_str.find("include")].strip().strip(string.whitespace + ",'\"/")

                if "" != node_name: node_name += "/" # 节点扩展（非常规应用程序名，如 'index/'）
                pop_path.split_path.append(node_name) # 此步骤非常重要！！！
                temp_app = App(node_name if node_name else '无缝衔接')
                pop_app.urls.append(temp_app) # 树节点扩展（仅扩展节点，不扩展数据行）
                for p in pop_path.children: # 将子路径推入栈中
                    p.relate_url = pop_path.relate_url + node_name
                    '''
                        在处理拆分路由时，必须让子路径继承父路径的所有拆分路由！！！（尽管最终显示的只有子路径拆分路由，这将直接影响路由的修改功能的效率）
                    '''
                    p.split_path.extend(pop_path.split_path)
                    stack_urls.append(PathHelper(p, temp_app))
        return show_nodes

    def _init_listree_data(self, data=None):
        """初始化树形列表"""

        '''
            数据包构建
        '''
        if data is None:
            data = self._get_bulid_data()
        self.model = ShowUrlsModel(data)
        self.treeListData.AssociateModel(self.model) # 通知控件使用该模型
        self.model.DecRef() # 渲染

        '''
            初始化列
        '''
        tr = wxdv.DataViewTextRenderer()
        col0 = wxdv.DataViewColumn("路由节点路径", tr, 0)
        self.treeListData.AppendColumn(col0)
        # col0 = self.treeListData.AppendTextColumn("", 0)
        # col0.SetMinWidth(240)
        col0.SetWidth(240)
        col0.SetAlignment(wx.ALIGN_LEFT)

        insert_columns = [
            # 列名、宽度、单元格性质、对齐方式、类型
            ("操作", 44, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendToggleColumn),
            ("路由级数", 66, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn),
            ("相对路由", 130, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_LEFT, self.treeListData.AppendTextColumn),
            ("代码生成方式", 120, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_LEFT, self.treeListData.AppendTextColumn),
            ("路由别名", 88, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn),
            ("全路由", 200, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_LEFT, self.treeListData.AppendTextColumn),
            ("路由拆解", 80, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_LEFT, self.treeListData.AppendTextColumn),
            ("归属应用程序", 120, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn),
            ("应用程序检索名称", 120, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn),
            ("归属文件", 180, wxdv.DATAVIEW_CELL_EDITABLE, wx.ALIGN_LEFT, self.treeListData.AppendTextColumn),
            # 末尾加一列空列（解决列表展示最后一列无法正常显示的BUG）
            ("", 1, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn),
        ]
        self._list_append_columns(insert_columns)

        # 允许排序
        for c in self.treeListData.Columns:
            c.Sortable = True
            c.Reorderable = True

        wx.CallAfter(col0.SetWidth, 240)

    def _list_append_columns(self, columns: List[object]):
        """列表添加列（从第二列开始自动添加）"""
        begin_index = 1
        for col in columns:
            col[-1](col[0], begin_index, width=col[1], mode=col[2], align=col[3])
            begin_index += 1

